
%{

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "common/log/log.h"
#include "common/lang/string.h"
#include "sql/parser/parse_defs.h"
#include "sql/parser/yacc_sql.hpp"
#include "sql/parser/lex_sql.h"
#include "sql/expr/expression.h"

using namespace std;

string token_name(const char *sql_string, YYLTYPE *llocp)
{
  return string(sql_string + llocp->first_column, llocp->last_column - llocp->first_column + 1);
}

int yyerror(YYLTYPE *llocp, const char *sql_string, ParsedSqlResult *sql_result, yyscan_t scanner, const char *msg)
{
  unique_ptr<ParsedSqlNode> error_sql_node = make_unique<ParsedSqlNode>(SCF_ERROR);
  error_sql_node->error.error_msg = msg;
  error_sql_node->error.line = llocp->first_line;
  error_sql_node->error.column = llocp->first_column;
  sql_result->add_sql_node(std::move(error_sql_node));
  return 0;
}

ArithmeticExpr *create_arithmetic_expression(ArithmeticExpr::Type type,
                                             Expression *left,
                                             Expression *right,
                                             const char *sql_string,
                                             YYLTYPE *llocp)
{
  ArithmeticExpr *expr = new ArithmeticExpr(type, left, right);
  expr->set_name(token_name(sql_string, llocp));
  return expr;
}

UnboundAggregateExpr *create_aggregate_expression(const char *aggregate_name,
                                           Expression *child,
                                           const char *sql_string,
                                           YYLTYPE *llocp)
{
  UnboundAggregateExpr *expr = new UnboundAggregateExpr(aggregate_name, child);
  expr->set_name(token_name(sql_string, llocp));
  return expr;
}

%}

%define api.pure full
%define parse.error verbose
/** 启用位置标识 **/
%locations
%lex-param { yyscan_t scanner }
/** 这些定义了在yyparse函数中的参数 **/
%parse-param { const char * sql_string }
%parse-param { ParsedSqlResult * sql_result }
%parse-param { void * scanner }

//标识tokens
%token  SEMICOLON
        BY
        CREATE
        DROP
        GROUP
        TABLE
        TABLES
        INDEX
        CALC
        SELECT
        DESC
        SHOW
        SYNC
        INSERT
        DELETE
        UPDATE
        LBRACE
        RBRACE
        COMMA
        TRX_BEGIN
        TRX_COMMIT
        TRX_ROLLBACK
        INT_T
        STRING_T
        FLOAT_T
        VECTOR_T
        DATE_T
        HELP
        EXIT
        DOT //QUOTE
        INTO
        VALUES
        FROM
        WHERE
        AND
        SET
        ON
        LOAD
        DATA
        INFILE
        EXPLAIN
        STORAGE
        FORMAT
        PRIMARY
        KEY
        ANALYZE
        EQ
        LT
        GT
        LE
        GE
        NE
        LK
        NOT_LK
        JOIN
        INNER
        UNIQUE
        NULL_T
        NOT
        IS
        IS_NOT
        AVG
        COUNT
        SUM
        MAX
        MIN
        HAVING
        ORDER_BY
        ASC
        IN
        NOT_IN
        EXISTS
        NOT_EXISTS
        AS
        TEXT_T
        OR
        

/** union 中定义各种数据类型，真实生成的代码也是union类型，所以不能有非POD类型的数据 **/
%union {
  ParsedSqlNode *                            sql_node;
  ConditionSqlNode *                         condition;
  Value *                                    value;
  enum CompOp                                comp;
  RelAttrSqlNode *                           rel_attr;
  vector<AttrInfoSqlNode> *                  attr_infos;
  AttrInfoSqlNode *                          attr_info;
  Expression *                               expression;
  vector<unique_ptr<Expression>> *           expression_list;
  vector<Value> *                            value_list;
  ConditionList *                             condition_list;
  vector<RelAttrSqlNode> *                   rel_attr_list;
  //vector<string> *                           relation_list;
  JoinNodeList *                             join_table_list;
  SetValueSqlNode*                           set_value_list;
  vector<string> *                           key_list;
  AliasNode *                                alias_node;
  vector<AliasNode> *                        alias_node_list;
  char *                                     cstring;                             
  int                                        number;
  float                                      floats;
  bool                                       is_unique;
  bool                                       is_nullable;
  vector<pair<unique_ptr<Expression>,bool>> *                order_by; 

}

%token <number> NUMBER
%token <floats> FLOAT
%token <cstring> ID
/*
%token <cstring> COUNT
%token <cstring> SUM
%token <cstring> AVG
%token <cstring> MAX
%token <cstring> MIN
*/
%token <cstring> DATE_STR
%token <cstring> SSS

//非终结符

/** type 定义了各种解析后的结果输出的是什么类型。类型对应了 union 中的定义的成员变量名称 **/
%type <number>              type
%type <condition>           condition
%type <value>               value
%type <number>              number
%type <cstring>             relation
%type <cstring>             agg_name
%type <comp>                comp_op
%type <rel_attr>            rel_attr
%type <attr_infos>          attr_def_list
%type <attr_info>           attr_def
%type <is_nullable>         nullable
%type <value_list>          value_list
%type <condition_list>      where
%type <order_by>            odlist
%type <order_by>            order_by_list
%type <alias_node>          alias_rel
%type <alias_node_list>     alias_rel_list

%type <condition_list>      condition_list
%type <condition_list>      on_list
%type <condition_list>      having_list
%type <cstring>             storage_format
%type <key_list>            primary_key
%type <key_list>            attr_list
//%type <relation_list>       rel_list
%type <join_table_list>     join_list  
%type <set_value_list>      set_list
%type <expression>          expression
%type <expression_list>     expression_list
%type <expression_list>     group_by
%type <sql_node>            calc_stmt
%type <sql_node>            select_stmt
%type <sql_node>            insert_stmt
%type <sql_node>            update_stmt
%type <sql_node>            delete_stmt
%type <sql_node>            create_table_stmt
%type <sql_node>            drop_table_stmt
%type <sql_node>            analyze_table_stmt
%type <sql_node>            show_tables_stmt
%type <sql_node>            desc_table_stmt
%type <sql_node>            create_index_stmt
%type <sql_node>            drop_index_stmt
%type <sql_node>            sync_stmt
%type <sql_node>            begin_stmt
%type <sql_node>            commit_stmt
%type <sql_node>            rollback_stmt
%type <sql_node>            load_data_stmt
%type <sql_node>            explain_stmt
%type <sql_node>            set_variable_stmt
%type <sql_node>            help_stmt
%type <sql_node>            exit_stmt
%type <sql_node>            command_wrapper
%type <is_unique>           unique_arg
// commands should be a list but I use a single command instead
%type <sql_node>            commands

%nonassoc '<' '>' '=' LE GE NE EQ LT GT LK NOT_LK IS IS_NOT IN NOT_IN EXISTS NOT_EXISTS AS
%left '+' '-'
%left '*' '/'
%right UMINUS

%%

commands: command_wrapper opt_semicolon  //commands or sqls. parser starts here.
  {
    unique_ptr<ParsedSqlNode> sql_node = unique_ptr<ParsedSqlNode>($1);
    sql_result->add_sql_node(std::move(sql_node));
  }
  ;

command_wrapper:
    calc_stmt
  | select_stmt
  | insert_stmt
  | update_stmt
  | delete_stmt
  | create_table_stmt
  | drop_table_stmt
  | analyze_table_stmt
  | show_tables_stmt
  | desc_table_stmt
  | create_index_stmt
  | drop_index_stmt
  | sync_stmt
  | begin_stmt
  | commit_stmt
  | rollback_stmt
  | load_data_stmt
  | explain_stmt
  | set_variable_stmt
  | help_stmt
  | exit_stmt
    ; 

exit_stmt:      
    EXIT {
      (void)yynerrs;  // 这么写为了消除yynerrs未使用的告警。如果你有更好的方法欢迎提PR
      $$ = new ParsedSqlNode(SCF_EXIT);
    };

help_stmt:
    HELP {
      $$ = new ParsedSqlNode(SCF_HELP);
    };

sync_stmt:
    SYNC {
      $$ = new ParsedSqlNode(SCF_SYNC);
    }
    ;

begin_stmt:
    TRX_BEGIN  {
      $$ = new ParsedSqlNode(SCF_BEGIN);
    }
    ;

commit_stmt:
    TRX_COMMIT {
      $$ = new ParsedSqlNode(SCF_COMMIT);
    }
    ;

rollback_stmt:
    TRX_ROLLBACK  {
      $$ = new ParsedSqlNode(SCF_ROLLBACK);
    }
    ;

drop_table_stmt:    /*drop table 语句的语法解析树*/
    DROP TABLE ID {
      $$ = new ParsedSqlNode(SCF_DROP_TABLE);
      $$->drop_table.relation_name = $3;
    };

analyze_table_stmt:  /* analyze table 语法的语法解析树*/
    ANALYZE TABLE ID {
      $$ = new ParsedSqlNode(SCF_ANALYZE_TABLE);
      $$->analyze_table.relation_name = $3;
    }
    ;

show_tables_stmt:
    SHOW TABLES {
      $$ = new ParsedSqlNode(SCF_SHOW_TABLES);
    }
    ;

desc_table_stmt:
    DESC ID  {
      $$ = new ParsedSqlNode(SCF_DESC_TABLE);
      $$->desc_table.relation_name = $2;
    }
    ;

create_index_stmt:    /*create index 语句的语法解析树*/
    CREATE unique_arg INDEX ID ON ID LBRACE attr_list RBRACE
    {
      $$ = new ParsedSqlNode(SCF_CREATE_INDEX);
      CreateIndexSqlNode &create_index = $$->create_index;
      create_index.is_unique=$2;
      create_index.index_name = $4;
      create_index.relation_name = $6;
      create_index.attribute_names.swap(*$8);
      delete $8;
    }
    ;
unique_arg:
      /* empty */
      {
        $$ = false;
      }
      | UNIQUE
      {
        $$ = true;
      }


drop_index_stmt:      /*drop index 语句的语法解析树*/
    DROP INDEX ID ON ID
    {
      $$ = new ParsedSqlNode(SCF_DROP_INDEX);
      $$->drop_index.index_name = $3;
      $$->drop_index.relation_name = $5;
    }
    ;
create_table_stmt:    /*create table 语句的语法解析树*/
    CREATE TABLE ID LBRACE attr_def attr_def_list primary_key RBRACE storage_format
    {
      $$ = new ParsedSqlNode(SCF_CREATE_TABLE);
      CreateTableSqlNode &create_table = $$->create_table;
      create_table.relation_name = $3;
      //free($3);

      vector<AttrInfoSqlNode> *src_attrs = $6;

      if (src_attrs != nullptr) {
        create_table.attr_infos.swap(*src_attrs);
        delete src_attrs;
      }
      create_table.attr_infos.emplace_back(*$5);
      reverse(create_table.attr_infos.begin(), create_table.attr_infos.end());
      delete $5;
      if ($7 != nullptr) {
        create_table.primary_keys.swap(*$7);
        delete $7;
      }
      if ($9 != nullptr) {
        create_table.storage_format = $9;
      }
    }
    |CREATE TABLE ID LBRACE attr_def attr_def_list primary_key RBRACE storage_format select_stmt
    {
      $$ = new ParsedSqlNode(SCF_CREATE_TABLE);
      CreateTableSqlNode &create_table = $$->create_table;
      create_table.relation_name = $3;
      //free($3);

      vector<AttrInfoSqlNode> *src_attrs = $6;

      if (src_attrs != nullptr) {
        create_table.attr_infos.swap(*src_attrs);
        delete src_attrs;
      }
      create_table.attr_infos.emplace_back(*$5);
      reverse(create_table.attr_infos.begin(), create_table.attr_infos.end());
      delete $5;
      if ($7 != nullptr) {
        create_table.primary_keys.swap(*$7);
        delete $7;
      }
      if ($9 != nullptr) {
        create_table.storage_format = $9;
      }
      if($10 != nullptr)
      {
        $$->selection = std::move($10->selection);
        delete $10;
      }
    }
    |
    |CREATE TABLE ID LBRACE attr_def attr_def_list primary_key RBRACE storage_format AS select_stmt
    {
      $$ = new ParsedSqlNode(SCF_CREATE_TABLE);
      CreateTableSqlNode &create_table = $$->create_table;
      create_table.relation_name = $3;
      //free($3);

      vector<AttrInfoSqlNode> *src_attrs = $6;

      if (src_attrs != nullptr) {
        create_table.attr_infos.swap(*src_attrs);
        delete src_attrs;
      }
      create_table.attr_infos.emplace_back(*$5);
      reverse(create_table.attr_infos.begin(), create_table.attr_infos.end());
      delete $5;
      if ($7 != nullptr) {
        create_table.primary_keys.swap(*$7);
        delete $7;
      }
      if ($9 != nullptr) {
        create_table.storage_format = $9;
      }
      if($11 != nullptr)
      {
        $$->selection = std::move($11->selection);
        delete $11;
      }
    }
    |
    CREATE TABLE ID AS select_stmt
    {
      $$ = new ParsedSqlNode(SCF_CREATE_TABLE);
      CreateTableSqlNode &create_table = $$->create_table;
      create_table.relation_name = $3;
      $$->selection = std::move($5->selection);
      delete $5;
    }
    ;
    
attr_def_list:
    /* empty */
    {
      $$ = nullptr;
    }
    | attr_def_list COMMA attr_def
    {
      if ($1 != nullptr) {
        $$ = $1;
      } else {
        $$ = new vector<AttrInfoSqlNode>;
      }
      $$->insert($$->begin(), *$3);
      delete $3;
    }
    ;
    
attr_def:
    ID type LBRACE number RBRACE nullable
    {
      $$ = new AttrInfoSqlNode;
      $$->type = (AttrType)$2;
      $$->name = $1;
      $$->length = $4;
      if($$->type==AttrType::TEXT) {
        $$->type = AttrType::CHARS;
        $$->length = 65535;
      }
      $$->is_nullable = $6;
    }
    | ID type nullable
    {
      $$ = new AttrInfoSqlNode;
      $$->type = (AttrType)$2;
      $$->name = $1;
      $$->length = 4;
      if($$->type==AttrType::TEXT) {
        $$->type = AttrType::CHARS;
        $$->length = 65535;
      }
      $$ -> is_nullable = $3;
    }
    ;
nullable:
    /* empty */
    {
      $$ = true;
    }
    | NULL_T
    {
      $$ = true;
    }
    | NOT NULL_T
    {
      $$ = false;
    }

number:
    NUMBER {$$ = $1;}
    ;
type:
    INT_T      { $$ = static_cast<int>(AttrType::INTS); }
    | STRING_T { $$ = static_cast<int>(AttrType::CHARS); }
    | FLOAT_T  { $$ = static_cast<int>(AttrType::FLOATS); }
    | VECTOR_T { $$ = static_cast<int>(AttrType::VECTORS); }
    | DATE_T   { $$ = static_cast<int>(AttrType::DATES); }
    | TEXT_T   { $$ = static_cast<int>(AttrType::TEXT); }
    ;
primary_key:
    /* empty */
    {
      $$ = nullptr;
    }
    | COMMA PRIMARY KEY LBRACE attr_list RBRACE
    {
      $$ = $5;
    }
    ;

attr_list:
    ID {
      $$ = new vector<string>();
      $$->push_back($1);
    }
    | ID COMMA attr_list {
      if ($3 != nullptr) {
        $$ = $3;
      } else {
        $$ = new vector<string>;
      }

      $$->insert($$->begin(), $1);
    }
    ;

insert_stmt:        /*insert   语句的语法解析树*/
    INSERT INTO ID VALUES LBRACE value value_list RBRACE 
    {
      $$ = new ParsedSqlNode(SCF_INSERT);
      $$->insertion.relation_name = $3;
      if ($7 != nullptr) {
        $$->insertion.values.swap(*$7);
        delete $7;
      }
      $$->insertion.values.emplace_back(*$6);
      reverse($$->insertion.values.begin(), $$->insertion.values.end());
      delete $6;
    }
    ;

value_list:
    /* empty */
    {
      $$ = nullptr;
    }
    | COMMA value value_list  { 
      if ($3 != nullptr) {
        $$ = $3;
      } else {
        $$ = new vector<Value>;
      }
      $$->emplace_back(*$2);
      delete $2;
    }
    ;
value:
    NUMBER {
      $$ = new Value((int)$1);
      @$ = @1;
    }
    |FLOAT {
      $$ = new Value((float)$1);
      @$ = @1;
    }
    | NULL_T {
      $$ = new Value();
      $$ -> set_null();
    }
    |DATE_STR{
      char *tmp = common::substr($1,1,strlen($1)-2);
      $$ = new Value(tmp);
      free(tmp);
    }
    |SSS {
      char *tmp = common::substr($1,1,strlen($1)-2);
      $$ = new Value(tmp);
      free(tmp);
    }
    ;
storage_format:
    /* empty */
    {
      $$ = nullptr;
    }
    | STORAGE FORMAT EQ ID
    {
      $$ = $4;
    }
    ;
    
delete_stmt:    /*  delete 语句的语法解析树*/
    DELETE FROM ID where 
    {
      $$ = new ParsedSqlNode(SCF_DELETE);
      $$->deletion.relation_name = $3;
      if ($4 != nullptr) {
        $$->deletion.conditions = *$4;
        delete $4;
      }
    }
    ;
update_stmt:      /*  update 语句的语法解析树*/
    UPDATE ID SET ID EQ expression set_list where 
    {
      $$ = new ParsedSqlNode(SCF_UPDATE);
      if($7!=nullptr)
      {
        $$->update.attribute_names.swap($7->attribute_names);
        $$->update.expressions.swap($7->expressions);
        delete $7;
      }
      $$->update.relation_name = $2;
      $$->update.attribute_names.emplace_back($4);
      $$->update.expressions.emplace_back($6);
      if ($8 != nullptr) {
        $$->update.conditions=*$8;
        delete $8;
      }
    }
    ;
select_stmt:        /*  select 语句的语法解析树*/
    SELECT expression_list FROM alias_rel_list join_list where group_by having_list order_by_list
    {
      $$ = new ParsedSqlNode(SCF_SELECT);
      if ($2 != nullptr) {
        $$->selection.expressions.swap(*$2);
        delete $2;
      }

      if ($4 != nullptr) {
        $$->selection.relations.swap(*$4);
        delete $4;
      }

      if ($6 != nullptr) {
        $$->selection.conditions = *$6;
        delete $6;
      }
      else 
      {
        $$->selection.conditions.logic_op=LogicOp::AND_;
      }

      if ($7 != nullptr) {
        $$->selection.group_by.swap(*$7);
        delete $7;
      } 
      if($5!=nullptr) {
        std::reverse($5->relations.begin(),$5->relations.end());
        $$->selection.relations.insert($$->selection.relations.end(),$5->relations.begin(),$5->relations.end());
        $$->selection.conditions.conditions.insert($$->selection.conditions.conditions.end(),$5->conditions.conditions.begin(),$5->conditions.conditions.end());
        delete $5;
      }
      if($8 != nullptr)
      {
        $$->selection.having.swap($8->conditions);
        delete $8;
      }
      if($9 != nullptr)
      {
        $$->selection.order_by.swap(*$9);
        delete $9;
      }
    }
    ;

order_by_list:
    /* empty */
    {
      $$ = nullptr;
    }
    | ORDER_BY odlist
    {
      $$ = $2;
    }

odlist:
    expression ASC
    {
      $$ = new vector<pair<unique_ptr<Expression>,bool>>;
      unique_ptr<Expression> ptr($1);
      $$->push_back({std::move(ptr),true});
    }
    | expression
    {
      $$ = new vector<pair<unique_ptr<Expression>,bool>>;
      unique_ptr<Expression> ptr($1);
      $$->push_back({std::move(ptr),true});
    }
    | expression DESC
    {
      $$ = new vector<pair<unique_ptr<Expression>,bool>>;
      unique_ptr<Expression> ptr($1);
      $$->push_back({std::move(ptr),false});
    }
    | odlist COMMA expression ASC
    {
      $$ = $1;
      unique_ptr<Expression> ptr($3);
      $$->push_back({std::move(ptr),true});
    }
    | odlist COMMA expression 
    {
      $$ = $1;
      unique_ptr<Expression> ptr($3);
      $$->push_back({std::move(ptr),true});
    }
    | odlist COMMA expression DESC
    {
      $$ = $1;
      unique_ptr<Expression> ptr($3);
      $$->push_back({std::move(ptr),false});
    }

calc_stmt:
    CALC expression_list
    {
      $$ = new ParsedSqlNode(SCF_CALC);
      $$->calc.expressions.swap(*$2);
      delete $2;
    }
    ;

expression_list:
    expression
    {
      $$ = new vector<unique_ptr<Expression>>;
      $$->emplace_back($1);
    }
    | expression COMMA expression_list
    {
      if ($3 != nullptr) {
        $$ = $3;
      } else {
        $$ = new vector<unique_ptr<Expression>>;
      }
      $$->emplace($$->begin(), $1);
    }
    ;
expression:
   
    expression '+' expression {
      $$ = create_arithmetic_expression(ArithmeticExpr::Type::ADD, $1, $3, sql_string, &@$);
    }
    | expression '-' expression {
      $$ = create_arithmetic_expression(ArithmeticExpr::Type::SUB, $1, $3, sql_string, &@$);
    }
    | expression '*' expression {
      $$ = create_arithmetic_expression(ArithmeticExpr::Type::MUL, $1, $3, sql_string, &@$);
    }
    | expression '/' expression {
      $$ = create_arithmetic_expression(ArithmeticExpr::Type::DIV, $1, $3, sql_string, &@$);
    }
    | agg_name LBRACE expression RBRACE {
      $$ = new UnboundAggregateExpr($1,$3);
      delete[] $1;
      $$->set_name(token_name(sql_string, &@$));
    }
    | LBRACE expression RBRACE {
      $$ = $2;
      $$->set_name(token_name(sql_string, &@$));
    }
    | '-' expression %prec UMINUS {
      $$ = create_arithmetic_expression(ArithmeticExpr::Type::NEGATIVE, $2, nullptr, sql_string, &@$);
    }
    | value {
      $$ = new ValueExpr(*$1);
      $$->set_name(token_name(sql_string, &@$));
      delete $1;
    } 
    | LBRACE value value_list RBRACE {
      ValueListExpr *tmp = new ValueListExpr();
      if($3!=nullptr)
      {
        tmp->swap(*$3);
        delete $3;
      }
      vector<Value>& vec = tmp->values();
      vec.emplace_back(*$2);
      reverse(vec.begin(),vec.end());
      $$ = tmp;
      delete $2;
    } 
   
    | rel_attr {
      RelAttrSqlNode *node = $1;
      $$ = new UnboundFieldExpr(node->relation_name, node->attribute_name);
      $$->set_name(token_name(sql_string, &@$));
      delete $1;
    }
    | LBRACE select_stmt RBRACE
    {
      $$ = new SubqueryExpr($2);
      $$->set_name(token_name(sql_string, &@$));
    }
    | ID DOT '*' {
      $$ = new StarExpr($1);
    }
    | '*' {
      $$ = new StarExpr();
    }
    | EXISTS expression {
      $$ = new ComparisonExpr(EXISTS_OP,nullptr,std::unique_ptr<Expression>($2));
      $$->set_name(token_name(sql_string, &@$));
     }
     | NOT_EXISTS expression {
      $$ = new ComparisonExpr(NOT_EXISTS_OP,nullptr,std::unique_ptr<Expression>($2));
      $$->set_name(token_name(sql_string, &@$));
     }
    // your code here
     |expression comp_op expression {
      $$ = new ComparisonExpr($2,std::unique_ptr<Expression>($1),std::unique_ptr<Expression>($3));
      $$->set_name(token_name(sql_string, &@$));
    }
     | expression AS ID {
      auto ptr = unique_ptr<Expression>($1);
      $$ = new AliasExpr($3,std::move(ptr));
     }
     | expression ID {
      auto ptr = unique_ptr<Expression>($1);
      $$ = new AliasExpr($2,std::move(ptr));
     }
    
     
     
    ;
agg_name:
  COUNT {
    $$ = new char [6];
    strcpy($$,"count");
  }
  | AVG {
    $$ = new char [6];
    strcpy($$,"avg");
  }
  | SUM {
    $$ = new char [6];
    strcpy($$,"sum");
  }
  | MAX {
    $$ = new char [6];
    strcpy($$,"max");
  }
  | MIN {
   $$ = new char [6];
    strcpy($$,"min");
  }
rel_attr:
    ID {
      $$ = new RelAttrSqlNode;
      $$->attribute_name = $1;
    }
    | ID DOT ID {
      $$ = new RelAttrSqlNode;
      $$->relation_name  = $1;
      $$->attribute_name = $3;
    }
    ;

relation:
    ID {
      $$ = $1;
    }
    ;
/*
rel_list:
    relation {
      $$ = new vector<string>();
      $$->push_back($1);
    }
    | relation COMMA rel_list {
      if ($3 != nullptr) {
        $$ = $3;
      } else {
        $$ = new vector<string>;
      }

      $$->insert($$->begin(), $1);
    }
    ;*/

alias_rel_list:
    alias_rel{
      $$ = new vector<AliasNode>();
      $$->push_back(*$1);
      delete $1;
    }
    | alias_rel_list COMMA alias_rel {
      $$ = $1;
      $$->push_back(*$3);
      delete $3;
    }

alias_rel:
    relation{
      $$ = new AliasNode;
      $$ -> table_name_ = $1;
    }
    | relation AS ID
    {
      $$ = new AliasNode;
      $$ -> table_name_ = $1;
      $$ -> alias_name_ = $3;
    }
    | relation ID
    {
      $$ = new AliasNode;
      $$ -> table_name_ = $1;
      $$ -> alias_name_ = $2;
    }

join_list:
    /* empty */
    {
      $$ = nullptr;
    }
    | INNER JOIN alias_rel on_list join_list
    {
      if ($5 != nullptr) {
        $$ = $5;
      } else {
        $$ = new JoinNodeList;
      }
      $$->relations.emplace_back(*$3);
      delete $3;
      if($4 != nullptr)
      {
        $$->conditions.conditions.insert($$->conditions.conditions.end(),$4->conditions.begin(),$4->conditions.end());
        delete $4;
      }
    }

on_list:
    /* empty */
    {
      $$ = nullptr;
    }
    | ON condition_list
    {
      $$ = $2;
    }


set_list:
    /* empty */
    {
      $$ = nullptr;
    }
    | COMMA ID EQ expression set_list{
      if ($5 != nullptr) {
        $$ = $5;
      } else {
        $$ = new SetValueSqlNode;
      }
      $$->attribute_names.push_back($2);
      $$->expressions.push_back($4);
    }
where:
    /* empty */
    {
      $$ = nullptr;
    }
    | WHERE condition_list {
      $$ = $2;  
    }
    ;
condition_list:
    /* empty */
    {
      $$ = nullptr;
    }
    | condition {
      $$ = new ConditionList;
      $$->conditions.emplace_back(*$1);
      delete $1;
      $$->logic_op=(LogicOp)0;
    }
    | condition AND condition_list {
      $$ = $3;
      $$->conditions.emplace_back(*$1);
      delete $1;
      $$->logic_op=(LogicOp)0;
    }
    | condition OR condition_list {
      $$ = $3;
      $$->conditions.emplace_back(*$1);
      delete $1;
      $$->logic_op=(LogicOp)1;
    }
    ;
condition:
    expression 
    {
      $$ = new ConditionSqlNode;
      $$->expr = $1;
    }

    ;

comp_op:
      EQ { $$ = EQUAL_TO; }
    | LT { $$ = LESS_THAN; }
    | GT { $$ = GREAT_THAN; }
    | LE { $$ = LESS_EQUAL; }
    | GE { $$ = GREAT_EQUAL; }
    | NE { $$ = NOT_EQUAL; }
    | LK {$$ = LIKE_OP;}
    | NOT_LK {$$ = NOT_LIKE_OP;}
    | IS_NOT {$$ = IS_NOT_OP;}
    | IS {$$ = IS_OP;}
    | IN {$$ = IN_OP;}
    | NOT_IN {$$ = NOT_IN_OP;}
    ;

// your code here
group_by:
    /* empty */
    {
      $$ = nullptr;
    }
    | GROUP BY expression_list
    {
      $$ = $3;
    }
    ;
having_list:
    /* empty */
    {
      $$ = nullptr;
    }
    | HAVING condition_list
    {
      $$ = $2;
    }


load_data_stmt:
    LOAD DATA INFILE SSS INTO TABLE ID 
    {
      char *tmp_file_name = common::substr($4, 1, strlen($4) - 2);
      
      $$ = new ParsedSqlNode(SCF_LOAD_DATA);
      $$->load_data.relation_name = $7;
      $$->load_data.file_name = tmp_file_name;
      free(tmp_file_name);
    }
    ;

explain_stmt:
    EXPLAIN command_wrapper
    {
      $$ = new ParsedSqlNode(SCF_EXPLAIN);
      $$->explain.sql_node = unique_ptr<ParsedSqlNode>($2);
    }
    ;

set_variable_stmt:
    SET ID EQ value
    {
      $$ = new ParsedSqlNode(SCF_SET_VARIABLE);
      $$->set_variable.name  = $2;
      $$->set_variable.value = *$4;
      delete $4;
    }
    ;

opt_semicolon: /*empty*/
    | SEMICOLON
    ;
%%
//_____________________________________________________________________
extern void scan_string(const char *str, yyscan_t scanner);

int sql_parse(const char *s, ParsedSqlResult *sql_result) {
  yyscan_t scanner;
  std::vector<char *> allocated_strings;
  yylex_init_extra(static_cast<void*>(&allocated_strings),&scanner);
  scan_string(s, scanner);
  int result = yyparse(s, sql_result, scanner);

  for (char *ptr : allocated_strings) {
    free(ptr);
  }
  allocated_strings.clear();

  yylex_destroy(scanner);
  return result;
}